package serverAndThreads;

import gui.Contact;

import java.awt.GridLayout;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.ConnectException;
import java.net.Socket;
import java.net.UnknownHostException;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Iterator;

import staticClasses.F;
import staticClasses.Port;

import Projektarbete.Group;

import Projektarbete.User;
import databas.Chat_DB;
import databas.User_DB;
import databas.Group_DB;

public abstract class ST {

	abstract void perform(ObjectInputStream in, ObjectOutputStream out)
			throws IOException, ClassNotFoundException;

	public static class NewUser extends ST {

		@Override
		void perform(ObjectInputStream in, ObjectOutputStream out)
				throws IOException, ClassNotFoundException {
			User user = (User) in.readObject();
			boolean bol = new User_DB().storeNewUser(user);
			out.writeObject(bol);
		}

	}

	public static class LoginUser extends ST {

		@Override
		void perform(ObjectInputStream in, ObjectOutputStream out)
				throws IOException, ClassNotFoundException {

			String userName = (String) in.readObject();
			String userPassword = (String) in.readObject();
			String userIP = (String) in.readObject();

			User user = new User_DB().loginUser(userName, userPassword, userIP);
			out.writeObject(user);

			// Om user inte 妑 null lyckades inloggningen, 妌dra d�dennes
			// onlinestatus f歳 anv妌darns alla kontakter
			if (user != null) {
				ArrayList<User> userList = new User_DB().loadContacts(user
						.getU_id());
				sendOutObjectsToUserList(Port.getClientPort(), userList,
						F.UPDATE_ONLINE_STATUS, user);
			}
		}

	}

	public static class ContacList extends ST {

		@Override
		void perform(ObjectInputStream in, ObjectOutputStream out)
				throws IOException, ClassNotFoundException {

			User user = (User) in.readObject();
			ArrayList<User> contactList = new User_DB().loadContacts(user
					.getU_id());
			out.writeObject(contactList);

		}

	}

	public static class CreateGroup extends ST {

		@Override
		void perform(ObjectInputStream in, ObjectOutputStream out)
				throws IOException, ClassNotFoundException {

			ArrayList<User> userList = new ArrayList<User>();
			Group group = (Group) in.readObject();
			new Group_DB().storeNewGroup(group);

			System.out.println("Group stored: " + group.getName()
					+ ", (Class_: ST):");

			userList = group.getMembers();

			sendOutObjectsToUserList(Port.getClientPort(), userList,
					F.ADD_TO_GROUP, group);
		}

	}

	public static class GroupList extends ST {

		@Override
		void perform(ObjectInputStream in, ObjectOutputStream out)
				throws IOException, ClassNotFoundException {
			User user = (User) in.readObject();
			out.writeObject(new Group_DB().getGroupListForUser(user.getU_id()));
		}

	}

	public static class LogOutUser extends ST {

		@Override
		void perform(ObjectInputStream in, ObjectOutputStream out)
				throws IOException, ClassNotFoundException {
			User user = (User) in.readObject();
			new User_DB().logOutUser(user.getU_id());
			System.out.println(user.getUserName() + ": is logging out");

			// �dra onlinestatus f歳 anv妌darns alla kontakter
			ArrayList<User> userList = new User_DB().loadContacts(user
					.getU_id());
			sendOutObjectsToUserList(Port.getClientPort(), userList,
					F.UPDATE_ONLINE_STATUS, user);

		}

	}

	public static class AddContact extends ST {

		@Override
		void perform(ObjectInputStream in, ObjectOutputStream out)
				throws IOException, ClassNotFoundException {

			User user = (User) in.readObject();
			String nameOrMail = (String) in.readObject();

			ArrayList<User> contact = new ArrayList<User>(1);
			contact.add(new User_DB().addContact(user.getU_id(), nameOrMail));

			out.writeObject(contact.get(0));

			if (contact.get(0) != null) {
				sendOutObjectsToUserList(Port.getClientPort(), contact,
						F.ADD_CONTACT, user);
				System.out.println(contact.get(0).getUserName()
						+ ": has been added by " + user.getUserName());
			}

		}

	}

	public static class RemoveContact extends ST {

		@Override
		void perform(ObjectInputStream in, ObjectOutputStream out)
				throws IOException, ClassNotFoundException {
			User user = (User) in.readObject();
			ArrayList<User> removeList = (ArrayList<User>) in.readObject();

			for (int i = 0; i < removeList.size(); i++) {
				new User_DB().removeFromFriends(user.getU_id(),
						removeList.get(i).getU_id());

			}
		}

	}

	public static class SaveStickyNote extends ST {

		@Override
		void perform(ObjectInputStream in, ObjectOutputStream out)
				throws IOException, ClassNotFoundException {
			int ID = (Integer) in.readObject();
			String message = (String) in.readObject();

			new Group_DB().saveStickyNote(ID, message);

			System.out.println("Message saved!");
			ArrayList<User> memberList = new Group_DB().getGroup(ID)
					.getMembers();

			// Skickar ut Stickynotes till alla i gruppen som är online!
			sendOutObjectsToUserList(Port.getClientChatPort(), memberList,
					F.SAVE_STICKY_NOTE, ID, message);
		}
	}

	public static class GetStickyNote extends ST {

		@Override
		void perform(ObjectInputStream in, ObjectOutputStream out)
				throws IOException, ClassNotFoundException {
			int ID = Integer.parseInt((String) in.readObject());

			ArrayList<String> message = new Group_DB().getStickyNote(ID);

			out.writeObject(message);
		}
	}

	public static class RemoveStickyNote extends ST {

		@Override
		void perform(ObjectInputStream in, ObjectOutputStream out)
				throws IOException, ClassNotFoundException {
			int ID = Integer.parseInt((String) in.readObject());
			String removeMsg = (String) in.readObject();

			new Group_DB().removeStickNote(ID, removeMsg);

		}
	}

	public static class SearchUser extends ST {

		@Override
		void perform(ObjectInputStream in, ObjectOutputStream out)
				throws IOException, ClassNotFoundException {

			String searchWord = (String) in.readObject();

			ArrayList<User> userList = new User_DB().searchUser(searchWord);

			out.writeObject(userList);

		}
	}

	public static class UpdateGroup extends ST {

		@Override
		void perform(ObjectInputStream in, ObjectOutputStream out)
				throws IOException, ClassNotFoundException {

			Group group = (Group) in.readObject();
			new Group_DB().updateGroup(group);
			sendOutObjectsToUserList(Port.getClientPort(), group.getMembers(),
					F.UPDATE_GROUP, group);

		}
	}

	public static class StartChat extends ST {

		@Override
		void perform(ObjectInputStream in, ObjectOutputStream out)
				throws IOException, ClassNotFoundException {

			ArrayList<User> userArrayList = (ArrayList<User>) in.readObject();
			int chatId = new Chat_DB().startChat(userArrayList);
			sendOutObjectsToUserList(Port.getClientChatPort(), userArrayList,
					F.NEW_CHAT_FUNCTION_NUMBER, chatId, userArrayList);
		}
	}

	public static class SendGroupMessage extends ST {
		@Override
		void perform(ObjectInputStream in, ObjectOutputStream out)
				throws IOException, ClassNotFoundException {

			int groupId = (Integer) in.readObject();
			String message = (String) in.readObject();

			Group group = new Group_DB().getGroup(groupId);
			ArrayList<User> userList = group.getMembers();
			sendOutObjectsToUserList(Port.getClientChatPort(), userList,
					F.GROUP_MESSAGE_FUNCTION_NUMBER, groupId, message);

		}

	}

	public static class ChatMessage extends ST {

		@Override
		void perform(ObjectInputStream in, ObjectOutputStream out)
				throws IOException, ClassNotFoundException {

			int chatId = (Integer) in.readObject();
			String chatMessage = (String) in.readObject();

			ArrayList<User> chatMemberList = new Chat_DB()
					.getUsersInChat(chatId);

			sendOutObjectsToUserList(Port.getClientChatPort(), chatMemberList,
					F.CHAT_MESSAGE_FUNCTION_NUMBER, chatId, chatMessage);

		}
	}

	public static class UserLeavingChat extends ST {

		@Override
		void perform(ObjectInputStream in, ObjectOutputStream out)
				throws IOException, ClassNotFoundException {

			int chatId = (Integer) in.readObject();
			User userLeaving = (User) in.readObject();

			ArrayList<User> chatMemberList = new Chat_DB()
					.getUsersInChat(chatId);

			sendOutObjectsToUserList(Port.getClientChatPort(), chatMemberList,
					F.USER_LEAVING_CHAT_FUNCTION_NUMBER, chatId, userLeaving);

		}
	}

	public static class SendObjectsToUsers implements Runnable {
		int port;
		ArrayList<User> userList;
		Object[] objects;

		public SendObjectsToUsers(int port, ArrayList<User> userList,
				Object... objects) {
			this.port = port;
			this.userList = userList;
			this.objects = objects;
		}

		@Override
		public void run() {
			if (port == Port.getConnectChatPort()) {
				for (int i = 0; i < objects.length; i++) {
					System.out.println(objects[i].toString());
				}
				System.out.println();
			}

			for (int i = 0; i < userList.size(); i++) {
				if (userList.get(i).isOnline()) {
					try {
						Socket socket = new Socket(userList.get(i).getIp(),
								port);

						ObjectOutputStream out = new ObjectOutputStream(
								socket.getOutputStream());

						for (int j = 0; j < objects.length; j++) {
							out.writeObject(objects[j]);
						}

						out.close();
						socket.close();

					} catch (UnknownHostException e) {
						System.out.println("UnknownHostExeption i ST: "
								+ userList.get(i).getUserName());
					} catch (IOException e) {
						e.printStackTrace();
						System.out.println("IOException i ST: "
								+ userList.get(i).getUserName() + "\nPort: "
								+ port);
					}
				}
			}
		}
	}

	protected void sendOutObjectsToUserList(int port, ArrayList<User> userList,
			Object... objects) {
		// Denna startar en tråd som exekverar utskrift av object till alla
		// användare i arrayen
		new Thread(new SendObjectsToUsers(port, userList, objects)).start();
	}

}
